home *** CD-ROM | disk | FTP | other *** search
- #include <AppKit.h>
- #include <InterfaceKit.h>
- #include <stdio.h>
- #include <math.h>
- #include <Message.h>
- #include <assert.h>
-
- int dist(BPoint p1, BPoint p2) {
- BPoint diff = p1-p2;
- return (int)sqrt(diff.x*diff.x + diff.y*diff.y);
- }
-
- /* A few consts to make the code easier to read */
- const int fully_opaque = 255;
- const int very_opaque = 230;
- const int three_fourths_opaque = 192;
- const int half_transparent = 128;
- const int three_fourths_transparent = 64;
- const int very_transparent = 25;
- const int fully_transparent = 0;
-
- char *opacityToOpacityName(int op) {
- if (op == fully_opaque) return "Fully opaque";
- else if (op == very_opaque) return "Very opaque";
- else if (op == three_fourths_opaque) return "75% opaque";
- else if (op == half_transparent) return "50% transparent";
- else if (op == three_fourths_transparent) return "75% transparent";
- else if (op == very_transparent) return "Very transparent";
- else if (op == fully_transparent) return "Fully transparent";
- else return "???";
- }
-
- rgb_color black = {0, 0, 0, 64};
- rgb_color white = {255, 255, 255, 0};
- rgb_color red = {255, 0, 0, 0};
- rgb_color green = {0, 255, 0, 0};
- rgb_color blue = {0, 0, 255, 0};
-
- bool operator==(rgb_color c1, rgb_color c2) {
- /* Ignore alpha component--just comparing colors */
- if (c1.red == c2.red && c1.green == c2.green && c1.blue == c2.blue) {
- return true;
- } else {
- return false;
- }
- }
-
- char *colorToColorName(rgb_color c) {
- if (c==black) return "Black";
- else if (c==white) return "White";
- else if (c==red) return "Red";
- else if (c==green) return "Green";
- else if (c==blue) return "Blue";
- else return "???";
- }
-
-
- const char *APP_SIGNATURE = "application/x-vnd.Be-DrawingModesDemo";
-
-
-
- /************* Class representing squares (the only thing we draw *************/
- class Square {
- public:
- /* A square is defined by its size/location (first arg), drawing mode (second arg), alpha mode
- settings (3rd and 4th args--meaningful only if the drawing mode is B_OP_ALPHA), a color,
- and an opacity (meaningful only if using a constant-source alpha drawing mode */
- Square(BRect r, drawing_mode dm, source_alpha alpha1, alpha_function alpha2, rgb_color color, int opacity)
- {
- /* Squares are maintained in a linked list representing
- layerwise ordering. */
- next = this;
- prev = this;
-
- /* Squares drawn using the B_PIXEL_ALPHA setting will be drawn
- as a gradated bitmap, going from completely transparent on
- the left edge of the square to completely opaque on the
- right edge. */
- if (alpha1 == B_PIXEL_ALPHA) {
- int width = (int)(r.right - r.left);
- int height = (int)(r.bottom - r.top);
- /* Create a bitmap of appropriate size */
- BBitmap *square = new BBitmap(BRect(0, 0, width, height), B_RGB_32_BIT, true);
- BView* sview = new BView(BRect(0, 0, width, height), "", B_FOLLOW_ALL_SIDES, (uint32)NULL);
- square->AddChild(sview);
- square->Lock();
- /* Draw lines of varying transparency to create the gradated bitmap */
- for(int i = 0; i<=width; i++) {
- color.alpha = (uint8)((float)i/width * 255);
- sview->SetHighColor(color);
- sview->StrokeLine(BPoint(i, 0), BPoint(i, height));
- }
- sview->Sync();
- square->RemoveChild(sview);
- square->Unlock();
- /* Save the bitmap so it can be drawn onscreen later */
- bitmap = square;
- }
-
- /* For squares drawn using the B_CONSTANT_ALPHA setting, we
- will need to remember the opacity. */
- color.alpha = opacity;
-
- rectangle = r;
- AssignModes(dm, alpha1, alpha2, color);
- }
-
- /* AssignModes() keeps the various drawing mode settings, so
- we can set them in whatever view we draw to */
- void AssignModes(drawing_mode drMode, source_alpha blend1, alpha_function blend2, rgb_color hi) {
- blendmode1 = blend1;
- blendmode2 = blend2;
- hiColor = hi;
- drawMode = drMode;
- }
-
- /* Retrieves saved modes, and sets them on aView */
- void UseModes(BView *aView) {
- aView->SetDrawingMode(drawMode);
- aView->SetBlendingMode(blendmode1, blendmode2);
- aView->SetHighColor(hiColor);
- }
-
- /* Insert d either after or before this square, in the
- linked list of squares */
- void Append(Square* d, bool before=false) {
- if (before) { prev->Append(d); }
- else {
- d->next = next;
- next->prev = d;
- d->prev = this;
- next = d;
- }
- }
-
- /* Remove this square from the linked list of squares */
- void RemoveFromList() {
- next->prev = prev;
- prev->next = next;
- prev = next = (Square*)NULL;
- }
-
- BPoint location;
- Square *next, *prev;
- drawing_mode drawMode;
- source_alpha blendmode1;
- alpha_function blendmode2;
- rgb_color hiColor;
- rgb_color loColor;
- BRect rectangle;
- BBitmap *bitmap;
-
- /* Draw a square into aView. If highlight is true, the square
- should be highlighted with a thick border (used to indicate
- it is the "topmost" square */
- virtual void Draw(BView *aView, bool highlight) {
- char *drawMode, *blendMode, *overlayMode, *drawSource = "";
- blendMode = "";
- overlayMode = "";
- UseModes(aView);
- source_alpha src;
- switch (aView->DrawingMode()) {
- case B_OP_COPY : {
- drawMode = "COPY";
- break;
- }
- case B_OP_INVERT : {
- drawMode = "INVERT";
- break;
- }
- case B_OP_ALPHA : {
- alpha_function fnc;
- aView->GetBlendingMode(&src, &fnc);
- switch (src) {
- case B_CONSTANT_ALPHA : {
- drawSource = "B_CONSTANT_ALPHA";
- break;
- }
- case B_PIXEL_ALPHA : {
- drawSource = "B_PIXEL_ALPHA";
- break;
- }
- default : {
- drawSource = "???_alpha";
- }
- }
- switch (fnc) {
- case B_ALPHA_OVERLAY : {
- drawMode = "B_ALPHA_OVERLAY";
- break;
- }
- case B_ALPHA_COMPOSITE : {
- drawMode = "B_ALPHA_COMPOSITE";
- break;
- }
- default : {
- drawMode = "ALPHA_???";
- break;
- }
- }
- break;
- }
- default: {
- drawMode = "???";
- break;
- }
- }
- if (src == B_CONSTANT_ALPHA) {
- aView->FillRect(rectangle);
- } else {
- aView->DrawBitmap(bitmap, rectangle);
- }
- rgb_color hi = aView->HighColor();
- aView->SetDrawingMode(B_OP_COPY);
- char *colorString = colorToColorName(aView->HighColor());
- aView->SetHighColor(black);
- if (highlight) {
- BRect r = BRect(rectangle);
- r.InsetBy(1, 1);
- int oldPenSize = (int)aView->PenSize();
- aView->SetPenSize(3);
- aView->StrokeRect(r);
- aView->SetPenSize(oldPenSize);
- } else {
- aView->StrokeRect(rectangle);
- }
- /* Draw text in inverted mode so it shows up better */
- aView->SetDrawingMode(B_OP_INVERT);
- aView->MovePenTo(BPoint(rectangle.left + 5, rectangle.top + 15));
- aView->DrawString("Color: ");
- aView->DrawString(colorString);
- aView->MovePenTo(BPoint(rectangle.left+5, rectangle.top+30));
- aView->DrawString(drawMode);
- aView->MovePenTo(BPoint(rectangle.left+5, rectangle.top+45));
- aView->DrawString(drawSource);
- aView->MovePenTo(BPoint(rectangle.left+5, rectangle.top+60));
- if (src == B_CONSTANT_ALPHA) {
- aView->DrawString(opacityToOpacityName(hi.alpha));
- } else {
- aView->DrawString("Variable opacity");
- }
- aView->SetDrawingMode(B_OP_COPY);
- }
-
- /* Returns true if the square contains p, false otherwise */
- bool Contains(BPoint p) {
- int t = (int)rectangle.top;
- int b = (int)rectangle.bottom;
- int l = (int)rectangle.left;
- int r = (int)rectangle.right;
-
- return l <= p.x && p.x <= r && t <= p.y && p.y <= b;
- }
-
- /* Returns true if the invoking square intersects the given BRect */
- bool Intersects(BRect where) {
- return rectangle.Intersects(where);
- }
-
- };
-
- class AlphaView : public BView {
- public:
- AlphaView(BRect rect, char* name, uint32 sides, uint32 flags)
- : BView(rect, name, sides, flags) {
- viewRect = rect;
- assert(viewRect.top == 0 && viewRect.left == 0);
- SetViewColor(B_TRANSPARENT_32_BIT);
- /* Offscreen bitmap is used for double-buffering, so we
- can avoid flicker */
- offscreenBitmap = new BBitmap(rect, B_RGB_32_BIT, true);
- offscreenView = new BView(rect, "", B_FOLLOW_NONE, (uint32)NULL);
- offscreenBitmap->AddChild(offscreenView);
- shapes = NULL;
- MakeShapes();
- }
-
- /* Create a bunch of shapes. */
- void MakeShapes() {
- rgb_color colors[] = {red, green, blue};
- int numOfColors = 3;
- int opacities[] = {fully_opaque, three_fourths_transparent, fully_transparent};
- int numOfOpacities = 3;
- int top, left;
- top = 0;
- shapes = NULL;
- for (int nc=0; nc < numOfColors; nc++) {
- for (int oi=0; oi < numOfOpacities; oi++) {
- top = 20 + (nc * 160);
- left = 20 + (oi * 160);
- Square *sq = new Square(BRect(left, top, left+140, top+140), B_OP_ALPHA, B_CONSTANT_ALPHA, B_ALPHA_OVERLAY, colors[nc], opacities[oi]);
-
- if (shapes==NULL) {
- shapes = sq;
- } else {
- shapes->Append(sq);
- }
- }
- }
- top += 160;
- for (int nc=0; nc < numOfColors; nc++) {
- left = 20 + (nc * 160);
- Square *sq = new Square(BRect(left, top, left+140, top+140 ), B_OP_ALPHA, B_PIXEL_ALPHA, B_ALPHA_OVERLAY, colors[nc], opacities[0]);
- shapes->Append(sq);
- }
- }
-
- Square* FindClickedOn(BPoint where) {
- if (shapes == NULL) {
- return (Square*)NULL;
- }
- else {
- Square *current = shapes;
- while(1) {
- if (current->Contains(where)) {
- Invalidate(shapes->rectangle);
- return current;
- }
- else { current = current->next; }
- if (current == shapes) return (Square*)NULL;
- }
- }
- }
- void MouseUp(BPoint where) {
- dragging = (Square *)NULL;
- }
-
- void MouseMoved(BPoint where, uint32 transit, const BMessage *message) {
- if (dragging != NULL) {
- if ((where - lastMousePos) != BPoint(0,0)) {
- Invalidate(dragging->rectangle);
- dragging->location += (where - lastMousePos);
- dragging->rectangle.OffsetBy(where - lastMousePos);
- lastMousePos = where;
- Invalidate(dragging->rectangle);
- Window()->UpdateIfNeeded();
- }
- }
-
- }
-
- void MouseDown(BPoint where) {
- int32 buttons;
- Window()->CurrentMessage()->FindInt32("buttons", &buttons);
- if (buttons == B_PRIMARY_MOUSE_BUTTON) {
- lastMousePos = where;
- dragging = FindClickedOn(where);
- if (dragging != NULL && dragging != shapes) {
- dragging->RemoveFromList();
- shapes->Append(dragging, true);
- shapes = dragging;
- SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
- }
- } else if (buttons == B_SECONDARY_MOUSE_BUTTON) {
- rgb_color c = GetPoint(where);
- printf("At pixel (%f, %f), R:%d, G:%d, B:%d, Alpha = %d\n", where.x, where.y, c.red, c.green, c.blue, c.alpha);
- }
- }
-
- /* Draw anything that needs to be drawn. */
- void Draw(BRect where) {
- Square *current;
- offscreenBitmap->Lock();
- offscreenView->SetLowColor(this->LowColor());
- offscreenView->SetHighColor(this->LowColor());
- offscreenView->FillRect(where);
- Square *last = current = shapes->prev;
- bool highlight = false;
- /* Iterate over everything in "shapes" */
- while(1) {
- /* If this is the topmost square, highlight it with a thick border */
- if (current->prev==last) { highlight = true; }
- /* Only draw a shape if it intersects "where", the invalidated rectangle */
- if (current->Intersects(where)) {
- /* Draw into the offscreen bitmap, to avoid flickering */
- current->Draw(offscreenView, highlight);
- }
- current = current->prev;
- /* If done all shapes, break out of the loop */
- if (current == last) { break; }
- }
- /* Draw the invalidated portion of the offscreen bitmap
- into the onscreen view */
- offscreenView->Sync();
- DrawBitmap(offscreenBitmap, where, where);
- offscreenBitmap->Unlock();
- }
-
- rgb_color GetPoint(BPoint where) {
- int bytesPerRow = offscreenBitmap->BytesPerRow();
- int width = (int)(viewRect.right - viewRect.left + 1);
- assert(width * 4 == bytesPerRow);
- int offset = (int)(where.y*width + where.x);
- rgb_color c = ((rgb_color *)offscreenBitmap->Bits())[offset];
- rgb_color c2;
- c2.blue = c.red;
- c2.green = c.green;
- c2.red = c.blue;
- c2.alpha = c.alpha;
- return c2;
- }
-
- BRect viewRect;
- Square *shapes;
- Square *dragging;
- BPoint lastMousePos;
- BBitmap *offscreenBitmap;
- BView *offscreenView;
- };
-
- class MyWindow : public BWindow {
- public:
- MyWindow(BRect frame)
- : BWindow(frame, "TITLE", B_TITLED_WINDOW, B_NOT_ZOOMABLE) {
- drawView = new AlphaView(this->Bounds(), NULL, B_FOLLOW_ALL_SIDES, B_WILL_DRAW);
- AddChild(drawView);
- Show();
- }
-
- // QuitRequested causes clicks on the window's "close"
- // button in the titlebar to quit the application. Without
- // this, we'd have to kill the application manually.
- bool QuitRequested() {
- be_app->PostMessage(B_QUIT_REQUESTED);
- return true;
- }
-
- void MessageReceived(BMessage* msg) {
- switch(msg->what) {
- default: {
- break;
- }
- }
- }
-
- private:
- AlphaView *drawView;
- };
-
- class MyApp : public BApplication {
- public:
- MyApp() : BApplication(APP_SIGNATURE) {
- BRect windowRect;
- windowRect.Set(50,50,600,800);
- MyWindow *w = new MyWindow(windowRect);
- w->SetTitle("Alpha Transparency Demo");
- }
- private:
- MyWindow *theWindow;
- };
-
- int main(void) {
- MyApp *theApp;
- theApp = new(MyApp);
- theApp->Run();
- delete theApp;
- }
-